package corp;

//import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

public class CorporateDAO {

	private static CorporateDAO instance;

	private String[] malePrefixes = { "Mr ", "", "Dr ", "Sir ", "Lord ", "",
			"Bishop ", "" };
	private String[] femalePrefixes = { "Mrs ", "", "Dr ", "Miss ", "Dame ",
			"", "Lady ", "" };
	private String[] maleNames = { "James ", "John ", "Robert ", "Michael ",
			"William ", "David ", "Richard ", "Joseph ", "Charles ", "Thomas ",
			"Christopher ", "Daniel ", "Matthew ", "Donald ", "Anthony ",
			"Paul ", "Mark ", "George ", "Steven ", "Kenneth ", "Andrew ",
			"Edward ", "Brian ", "Joshua ", "Kevin ", "Ronald ", "Timothy ",
			"Jason ", "Jeffrey ", "Gary ", "Ryan ", "Eric ", "Nicholas ",
			"Stephen ", "Jacob ", "Frank ", "Larry ", "Jonathan ", "Scott ",
			"Justin ", "Raymond ", "Brandon ", "Gregory ", "Samuel ",
			"Patrick ", "Benjamin ", "Jack ", "Dennis ", "Jerry ", "Alexander " };

	private String[] femaleNames = { "Mary ", "Patricia ", "Elizabeth ",
			"Jennifer ", "Linda ", "Barbara ", "Susan ", "Margaret ",
			"Dorothy ", "Jessica ", "Sarah ", "Betty ", "Nancy ", "Karen ",
			"Lisa ", "Helen ", "Sandra ", "Donna ", "Ashley ", "Kimberly ",
			"Carol ", "Michelle ", "Amanda ", "Emily ", "Melissa ", "Laura ",
			"Deborah ", "Stephanie ", "Rebecca ", "Sharon ", "Ruth ",
			"Cynthia ", "Kathleen ", "Anna ", "Shirley ", "Amy ", "Angela ",
			"Virginia ", "Brenda ", "Catherine ", "Pamela ", "Katherine ",
			"Christine ", "Nicole ", "Janet ", "Debra ", "Carolyn ", "Rachel ",
			"Samantha ", "Heather " };

	private String[] surnames = { "Smith", "Jones", "Taylor", "Williams",
			"Brown", "Davies", "Evans", "Wilson", "Thomas", "Roberts",
			"Johnson", "Lewis", "Walker", "Robinson", "Wood", "Thompson",
			"White", "Watson", "Jackson", "Wright", "Green", "Harris",
			"Cooper", "King", "Lee", "Martin", "Clarke", "James", "Morgan",
			"Hughes", "Edwards", "Hill", "Moore", "Clark", "Harrison", "Scott",
			"Young", "Morris", "Hall", "Ward", "Turner", "Carter", "Phillips",
			"Mitchell", "Patel", "Adams", "Campbell", "Anderson", "Allen",
			"Cook", "Bailey", "Parker", "Miller", "Davis", "Murphy", "Price",
			"Bell", "Baker", "Griffiths", "Kelly", "Simpson", "Marshall",
			"Collins", "Bennett", "Cox", "Richardson", "Fox", "Gray", "Rose",
			"Chapman", "Hunt", "Robertson", "Shaw", "Reynolds", "Lloyd",
			"Ellis", "Richards", "Russell", "Wilkinson", "Khan", "Graham",
			"Stewart", "Reid", "Murray", "Powell", "Palmer", "Holmes",
			"Rogers", "Stevens", "Walsh", "Hunter", "Thomson", "Matthews",
			"Ross", "Owen", "Mason", "Knight", "Kennedy", "Butler", "Saunders",
			"Cole", "Pearce", "Dean", "Foster", "Harvey", "Hudson", "Gibson",
			"Mills", "Berry", "Barnes", "Pearson", "Kaur", "Booth", "Dixon",
			"Grant", "Gordon", "Lane", "Harper", "Ali", "Hart", "Mcdonald",
			"Brooks", "Ryan", "Carr", "Macdonald", "Hamilton", "Johnston",
			"West", "Gill", "Dawson", "Armstrong", "Gardner", "Stone",
			"Andrews", "Williamson", "Barker", "George", "Fisher",
			"Cunningham", "Watts", "Webb", "Lawrence", "Bradley", "Jenkins",
			"Wells", "Chambers", "Spencer", "Poole", "Atkinson", "Lawson" };

	private String[] fixedCM = {"","374100146221000",
			"374692067151003",
			"376701001541001",
			"373280269101066",
			"376060000231001",
			"376930309362006",
			"374988036941114",
			"374660001931004",
			"375380000742026"};
	
	private Random gen;
	
	private int highestAccNumber;

	public Map<String, Corporation> corporations;

	// Index to map CM number to corporation and control account #
	// Not yet used but possibly useful
	private Map<String, CardIndex> corpIndex;

	public synchronized static CorporateDAO getInstance() {
		if (instance == null) {
			instance = new CorporateDAO();
		}
		return instance;
	}

	private CorporateDAO() {
		highestAccNumber = 1;
		gen = new Random();
		corpIndex = new LinkedHashMap<String, CardIndex>();
		corporations = new LinkedHashMap<String, Corporation>();
		init();
	}
	
	public Map<String, CardIndex> getCardIndexObj(){
		return corpIndex;
	}

	public CardIndex getCardIndex(String cm) {
		return corpIndex.get(cm);
	}
	
	public void putCardIndex(String cm, CardIndex cIX) {
		corpIndex.put(cm, cIX);
	}

	private void init() {

		// Fixed # of corporations
		int corporationNo = 9;
		//http://brendoman.com/media/users/dan/finctional_companies.txt
		String[] corporationNames = { "", "Mega Industries",
				"Globex Corporation", "Corellian Engineering Corporation",
				"The Legitimate Businessmens Club", "Transworld Consortium" ,
				"Gizmonic Institute", "General Services Corporation" ,
				"C.H. Lavatory and Sons" , "Sirius Cybernetics Corporation" };
		// max number of control / card accounts per corp
		int controlAccounts = 8;
		int cardMembers = 20;
		Iterator it;
		int temp;

		for (int i = 1; i <= corporationNo; i++) {
			String s = new String(corporationNames[i]);
			String n = new String("00000" + i);
			addCorporation(new Corporation(n, s));
		}

		it = corporations.values().iterator();

		while (it.hasNext()) {
			temp = gen.nextInt(controlAccounts);
			temp++;
			Corporation corp = (Corporation) it.next();
			for (int k = 1; k <= temp; k++) {
				String s = corp.getCorporationName() + "; Control Account " + k;
				String n = "000" + k;
				corp.addControlAccount(new ControlAccount(n, s));
			}
		}

		Iterator it2 = corporations.values().iterator();
		int corpNum = 0;
		boolean firstCM;

		while (it2.hasNext()) {
			Corporation corp = (Corporation) it2.next();
			corpNum++;
			firstCM = true;
			Iterator it3 = corp.getControlAccounts().values().iterator();
			while (it3.hasNext()) {
				temp = gen.nextInt(cardMembers);
				temp++;
				ControlAccount ctrl = (ControlAccount) it3.next();
				for (int l = 1; l <= temp; l++) {
					String name = generateName(gen.nextBoolean());
					String number;
					if (firstCM) {
						number = fixedCM[corpNum];
						firstCM = false;
					} else {
						number = genAccountNumber(highestAccNumber);
					}
					CardAccount cm = new CardAccount(number, name);
					System.out.print("Number added: " + number
							+ ", Corporation " + corp.getCorporationNumber()
							+ "," + ctrl.getControlAccountNumber() + ".");
					int d = gen.nextInt(100000);
					cm.setBalance(d);
					System.out.println("Balance: " + cm.getFormattedBalance());
					ctrl.addCardAccount(cm);
					// Add to control / corp balance
					ctrl.debitControlAccount(d);
					corp.debitCorporation(d);
					corpIndex.put(
							cm.getCardNumber(),
							new CardIndex(corp.getCorporationNumber(), ctrl
									.getControlAccountNumber()));
					highestAccNumber++;
				}
			}
		}

	}
	
	// Adds a new card account
	protected boolean addNewCardAccount(String name, String corpId, String ctrlAcc) {
		String accNo = genAccountNumber(highestAccNumber);
		Corporation co = fetchCorporation(corpId);
		if (co == null)
			return false;
		ControlAccount ca = co.getControlAccount(ctrlAcc);
		if (ca == null)
			return false;
		boolean b = ca.addCardAccount(new CardAccount(accNo, name));
		if (b) {
			highestAccNumber++;
			return true;
		}
		return false;
	}

	// Generate a random account number
	private String genAccountNumber(int number) {
		StringBuffer buff = new StringBuffer();
		buff.append(number);
		buff.reverse();
		while (buff.length() < 4) {
			buff.append("0");
		}
		while (buff.length() < 10) {
			int rand = gen.nextInt(9);
			buff.append(rand);
		}
		buff.append("19943");
		buff.reverse();
		boolean exists = false;
		for (int i = 0; i < fixedCM.length; i++) {
			if (buff.toString().equals(fixedCM[i])) {
				exists = true;
				break;
			}
		}
		if (exists)
			return genAccountNumber(number);
		else
			return buff.toString();
	}

	private void addCorporation(Corporation c) {
		corporations.put(c.getCorporationNumber(), c);
	}

	protected Map<String, Corporation> getCorporation() {
		return corporations;
	}

	protected Corporation fetchCorporation(String corpNumber) {
		return corporations.get(corpNumber);
	}

	protected Corporation fetchCorporationByName(String corpName) {
		Iterator it = corporations.values().iterator();
		while (it.hasNext()) {
			Corporation corp = (Corporation) it.next();
			if (corp.getCorporationName().equalsIgnoreCase(corpName)) {
				return corp;
			}
		}
		return null;
	}

	protected CardAccount fetchCardAccount(String cardNumber) {
		Iterator it = corporations.values().iterator();
		while (it.hasNext()) {
			Corporation corp = (Corporation) it.next();
			Iterator it2 = corp.getControlAccounts().values().iterator();
			while (it2.hasNext()) {
				ControlAccount ctrlAcc = (ControlAccount) it2.next();
				CardAccount acct = ctrlAcc.getCardAccount(cardNumber);
				if (acct != null) {
					return acct;
				}
			}
		}
		return null;
	}

	protected ControlAccount fetchControlAccount(String accountNumber) {
		Iterator it = corporations.values().iterator();
		while (it.hasNext()) {
			Corporation corp = (Corporation) it.next();
			ControlAccount acc = corp.getControlAccount(accountNumber);
			if (acc != null) {
				return acc;
			}
		}
		return null;
	}

	protected String generateName(boolean gender) {
		StringBuffer buff = new StringBuffer();
		if (gender) {
			int a = gen.nextInt((malePrefixes.length) - 1);
			buff.append(malePrefixes[a]);
			int b = gen.nextInt((maleNames.length) - 1);
			buff.append(maleNames[b]);
			int c = gen.nextInt((surnames.length) - 1);
			buff.append(surnames[c]);
		} else {
			int a = gen.nextInt((femalePrefixes.length) - 1);
			buff.append(femalePrefixes[a]);
			int b = gen.nextInt((femaleNames.length) - 1);
			buff.append(femaleNames[b]);
			int c = gen.nextInt((surnames.length) - 1);
			buff.append(surnames[c]);
		}
		return buff.toString();
	}

}
